﻿using System;
using System.Collections.Generic;
using System.Linq.Expressions;

namespace TelerikMvcGridCustomBindingHelper
{
    public interface IBaseCaseOptions
    {
        void ServerSideOnly();
        void ClientSideOnly();
        void BothClientAndServerSide(bool useCaseInsensitiveSearchOnBothClientAndServerSide = true);
    }

    public interface ICaseOptions<TEntity> : IBaseCaseOptions
    {
        new ICaseOptions<TEntity> ServerSideOnly();
        new ICaseOptions<TEntity> ClientSideOnly();
        ICaseOptions<TEntity> Ignore(Expression<Func<TEntity, object>> selector);
        ICaseOptions<TEntity> Use(Expression<Func<TEntity, object>> selector);
    }

    internal class CaseInsensitive<TEntity> : ICaseOptions<TEntity>
    {
        private bool _isDefault = true;
        public bool ShouldBeOnServerSide { get; private set; }
        public bool ShouldBeOnClientSide { get; private set; }
        internal readonly List<LambdaExpression> PropertiesToIgnore = new List<LambdaExpression>();
        internal readonly List<LambdaExpression> PropertiesToUse = new List<LambdaExpression>();

        public CaseInsensitive() { }

        public CaseInsensitive(bool shouldBeOnServerSide, bool shouldBeOnClientSide)
        {
            ShouldBeOnServerSide = shouldBeOnServerSide;
            ShouldBeOnClientSide = shouldBeOnClientSide;
            _isDefault = false;
        }

        ICaseOptions<TEntity> ICaseOptions<TEntity>.ServerSideOnly()
        {
            ShouldBeOnServerSide = true;
            ShouldBeOnClientSide = false;
            _isDefault = false;
            return this;
        }

        ICaseOptions<TEntity> ICaseOptions<TEntity>.ClientSideOnly()
        {
            ShouldBeOnClientSide = true;
            ShouldBeOnServerSide = false;
            _isDefault = false;
            return this;
        }

        public void BothClientAndServerSide(bool useCaseInsensitiveSearchOnBothClientAndServerSide)
        {
            ((ICaseOptions<TEntity>)this).BothClientAndServerSide(useCaseInsensitiveSearchOnBothClientAndServerSide);
        }

        void IBaseCaseOptions.BothClientAndServerSide(bool useCaseInsensitiveSearchOnBothClientAndServerSide)
        {
            ShouldBeOnClientSide = ShouldBeOnServerSide = useCaseInsensitiveSearchOnBothClientAndServerSide;
            _isDefault = false;
        }

        void IBaseCaseOptions.ClientSideOnly()
        {
            ((ICaseOptions<TEntity>)this).ClientSideOnly();
        }

        void IBaseCaseOptions.ServerSideOnly()
        {
            ((ICaseOptions<TEntity>)this).ServerSideOnly();
        }

        ICaseOptions<TEntity> ICaseOptions<TEntity>.Ignore(Expression<Func<TEntity, object>> selector)
        {
            PropertiesToIgnore.Add(selector);

            if (_isDefault)
            {
                BothClientAndServerSide(true);
            }

            return this;
        }

        ICaseOptions<TEntity> ICaseOptions<TEntity>.Use(Expression<Func<TEntity, object>> selector)
        {
            PropertiesToUse.Add(selector);

            if (_isDefault)
            {
                BothClientAndServerSide(true);
            }

            return this;
        }

        public void CopyFrom<TCaseInsensitiveEntity>(IBaseCaseOptions baseCaseOptions)
        {
            var opt = (CaseInsensitive<TCaseInsensitiveEntity>)baseCaseOptions;

            if (opt == null)
                return;

            ShouldBeOnClientSide = opt.ShouldBeOnClientSide;
            ShouldBeOnServerSide = opt.ShouldBeOnServerSide;

            _isDefault = false;
        }
    }
}